use std::{
    cell::UnsafeCell,
    mem::MaybeUninit,
    ops::{BitAnd, Deref, Shl},
};

unsafe impl<T: Send> Send for UninitMutCell<T> {}
unsafe impl<T: Sync> Sync for UninitMutCell<T> {}

#[repr(transparent)]
pub struct UninitMutCell<T>(UnsafeCell<MaybeUninit<T>>);

impl<T> Deref for UninitMutCell<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        unsafe { (&(*self.0.get())).assume_init_ref() }
    }
}

impl<T> UninitMutCell<T> {
    pub const fn const_new() -> Self {
        Self(UnsafeCell::new(MaybeUninit::uninit()))
    }

    pub unsafe fn write(&self, value: T) {
        (&mut (*self.0.get())).write(value);
    }

    pub unsafe fn read(&self) -> T {
        (&(*self.0.get())).assume_init_read()
    }

    pub unsafe fn drop(&self) {
        (&mut (*self.0.get())).assume_init_drop();
    }

    pub const unsafe fn as_mut(&self) -> &mut T {
        (&mut (*self.0.get())).assume_init_mut()
    }
}

pub fn new_buf(len: usize) -> Box<[u8]> {
    let mut buf = Vec::with_capacity(len);
    unsafe {
        buf.set_len(len);
    }
    buf.into_boxed_slice()
}

pub trait BitSet {
    fn is_set(self, bit_index: u8) -> bool;
}

impl<T: BitAnd<Output = T> + Copy + From<u8> + Shl<u8, Output = T> + PartialEq> BitSet for T {
    fn is_set(self, bit_index: u8) -> bool {
        let mask = T::from(1u8) << bit_index;
        (self & mask) != T::from(0)
    }
}
